package jsu.blogger;


import jsu.blogger.config.RedisKeyPrefixConfig;
import jsu.blogger.service.inter.PostService;
import jsu.blogger.util.FileUtil;
import org.junit.jupiter.api.Test;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class testBlogPostService {

    @Autowired
    private RedisTemplate<String,Object>redisTemplate;

    private void setUserOffset(Long userId, Long offset) {
        String key = RedisKeyPrefixConfig.USER_HASH_INTEREST_OFFSET; // Hash 表的名称
        // 将用户 ID 和 offset 存储在 Hash 表中
        redisTemplate.opsForHash().put(key, userId.toString(), offset);
    }
    private Long getUserOffset(Long userId) {
        String key = RedisKeyPrefixConfig.USER_HASH_INTEREST_OFFSET; // Hash 表的名称
        // 从 Hash 表中获取指定用户的 offset
        Object offset = redisTemplate.opsForHash().get(key, userId.toString());
        return offset != null ? Long.valueOf(offset.toString()) : null; // 返回对应的 offset，若不存在则返回 null
    }
    private void setRemainingRecommendations(Long userId, Long remainingCount) {
        // 将未推荐的剩余数量存储到哈希中，键为 "user:recommendations"，字段为 userId，值为 remainingCount
        redisTemplate.opsForHash().put(RedisKeyPrefixConfig.USER_HASH_RECOMMENDATIONS, userId.toString(), remainingCount);
    }

    private Long getRemainingRecommendations(Long userId) {
        // 从 Hash 表中获取指定用户的 offset
        Object offset = redisTemplate.opsForHash().get(RedisKeyPrefixConfig.USER_HASH_RECOMMENDATIONS, userId.toString());
        return offset != null ? Long.valueOf(offset.toString()) : null; // 返回对应的 offset，若不存在则返回 null
    }
    private List<String> getInterestTagNames(Long userId) {
        String key = RedisKeyPrefixConfig.getUserInterestTagsKey(userId);
        // 从 Redis 中获取所有的标签信息
        Map<Object, Object> tagInfo = redisTemplate.opsForHash().entries(key);
        // 创建一个 List 用于存储符合条件的标签名称
        List<String> result = new ArrayList<>();
        // 遍历所有标签信息并筛选符合条件的标签
        for (Map.Entry<Object, Object> entry : tagInfo.entrySet()) {
            String tagName = (String) entry.getKey();
            Map<String, Object> tagDetails = (Map<String, Object>) entry.getValue();
            // 假设权重存储在 tagDetails 中的 "weight" 键下
            if (tagDetails.containsKey("weight")) {
                Integer weight = (Integer) tagDetails.get("weight");
                // 仅添加权重大于等于 5.jpg 的标签名称
                if (weight != null && weight >= 5) {
                    result.add(tagName);
                }
            }
        }
        return result; // 返回符合条件的标签名称列表
    }
    @Autowired
    PostService postService;
    @Autowired
    private RedissonClient redissonClient;
    private static final String LOCK_KEY = "lock:create:recommendedBlog:list"; // 锁的键名
    private void addBolgIdsToRecommendedList(Long userId, Long offset, Long needCount) {
        if (offset != null && needCount != null && needCount > 0) {
            String lockKey = LOCK_KEY + userId;
            RLock lock = redissonClient.getLock(lockKey);
            int addedCount = 0;
            try {
                // 尝试获取锁，最多等待 10 秒，锁的持有时间为 30 秒
                if (lock.tryLock(10,30, TimeUnit.SECONDS)) {
                    while (true) {
                        List<String> tagNames = getInterestTagNames(userId);
                        long count = new Random().nextInt(5) + needCount;
                        // System.out.println(count);
                        List<Long> blogIds = postService.getPostIdsWithTags(tagNames, offset+addedCount, count);
                        // System.out.println(blogIds);
                        // 数据库无更多数据
                        boolean haveMore = Long.parseLong(String.valueOf(blogIds.size())) == count;
                        String recommendedBlogKey = RedisKeyPrefixConfig.getUserRecommendedBlogKey(userId);
                        long currentTimeMillis = System.currentTimeMillis();
                        // 检查 ZSET 是否存在
                        if (Boolean.FALSE.equals(redisTemplate.hasKey(recommendedBlogKey))) {
                            // 如果 ZSET 不存在，直接添加所有 blogId
                            for (Long blogId : blogIds) {
                                redisTemplate.opsForZSet().add(recommendedBlogKey, blogId.toString(), currentTimeMillis);
                                addedCount++;
                            }
                        } else {
                            // ZSET 存在，逐个检查并添加
                            for (Long blogId : blogIds) {
                                if (redisTemplate.opsForZSet().score(recommendedBlogKey, blogId.toString()) == null) {
                                    redisTemplate.opsForZSet().add(recommendedBlogKey, blogId.toString(), currentTimeMillis);
                                    addedCount++;
                                }
                            }
                        }

                        // 设置当前已经查询所在的offset
                        setUserOffset(userId, haveMore ? offset + addedCount : -1);
                        // 剩余未被推荐的博客id
                        Long recommendations = getRemainingRecommendations(userId);
                        if (recommendations == null) {
                            recommendations = 0L;
                        }
                        setRemainingRecommendations(userId, recommendations + addedCount);
                        if (!haveMore || recommendations + addedCount >= needCount) {
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                // 处理获取锁失败或其他异常
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    private List<String> testRecommendedBlogsId( Long userId, Long  count){
        if(count<=0){
            return Collections.emptyList();
        }
        //1.uid不存在 或者 uid存在但是redis没有记录用户感兴趣标签 或者 用户没有添加兴趣标签 ---->推送热点博客
        if (userId != null) {
            //2.redis记录的用户感兴趣标签
            String tagsKey = RedisKeyPrefixConfig.getUserInterestTagsKey(userId);
            if (Boolean.TRUE.equals(redisTemplate.hasKey(tagsKey))) {
                //3.设置推荐博客的键
                String recommendedBlogKey=RedisKeyPrefixConfig.getUserRecommendedBlogKey(userId);
                ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
                //4.获取当前用户兴趣标签分页查询所在的offset
                Long currOffset= getUserOffset(userId);
                if(currOffset==null){
                    //初始化
                    setUserOffset(userId,0L);
                    currOffset=0L;
                }
                //5.jpg.数据库还有数据可供查询 ----如果存放的是-1 则表示数据库无更多的推荐了
                boolean haveMore=currOffset!=-1L;
                if(Boolean.FALSE.equals(redisTemplate.hasKey(recommendedBlogKey))){
                    //5.jpg.推荐的博客列表不存在 空表并且数据库无数据查询
                    if(!haveMore) {
                        return Collections.emptyList();
                    }
                    //6.添加
                    addBolgIdsToRecommendedList(userId,currOffset,count);
                    haveMore=false;
                }
                Long recommendations=getRemainingRecommendations(userId);
                if( recommendations==null){
                    recommendations=0L;
                }else{
                    //推荐表存在 haveMore数据库有数据 但是未推荐的数量小于count
                    if(haveMore && recommendations<count){
                        addBolgIdsToRecommendedList(userId,currOffset,count);
                        //修改剩余推荐的数据
                        Long tepRecommendations=getRemainingRecommendations(userId);
                        recommendations=tepRecommendations!=null?tepRecommendations:0;
                    }
                }
                if(recommendations==0){
                    return Collections.emptyList();
                }
                // 将 recommendations 转换为负数
                long start= -Math.abs(recommendations);
                //System.out.println(start);
                long end=start+count-1;
                if(recommendations<=count){
                    end=-1L;
                    setRemainingRecommendations(userId,0L);
                }else{
                    setRemainingRecommendations(userId,recommendations-count);
                }
                //除去了其他情况
                Set<Object> recommendedBlogIds = zSetOperations.range(recommendedBlogKey,start,end);
                return recommendedBlogIds != null
                        ? recommendedBlogIds.stream().map(String::valueOf).collect(Collectors.toList())
                        : Collections.emptyList();
            }//可以从redis获取用户感兴趣标签
        }
        return Collections.emptyList();
    }

    @Test
    void main(){
        List<String> blogIds= testRecommendedBlogsId(1L,2L);
        System.out.println(blogIds);
//        String recommendedBlogKey = RedisKeyPrefixConfig.getUserRecommendedBlogKey(1L);
//        redisTemplate.opsForZSet().add(recommendedBlogKey, String.valueOf(1L), 123445);
    }



}
